大家好,我是 Yubin
我們在開發網頁後端的時候,常常會需要定義一些 API。本篇講一下透過 Fastify 的 Route 來定義 API Endpoint。
API,Application Programming Interface,應用程式介面。
這裡指的 API 可以想像成是你的系統,對外開出去的介面,對外開出去給別人使用的服務。
別人只能透過那些介面來跟你互動。
就像你去銀行想領錢,銀行是一個很大的系統,而且不是你管理的系統。
銀行提供了一些介面可以讓你領錢,例如櫃台人員、提款機。你只能透過櫃台人員或提款機,透過特定的動作、提交特定的資訊,才能完成領錢這個工作。
以銀行的角度來說,櫃台人員跟提款機就是銀行提供出去的介面。經過這些介面來提供提款服務給使用者,而不是讓使用者自己到金庫中拿取自己的財產。
以網頁系統來說,基於安全還有其他一堆有的沒的問題,我們也不會把自己的資料庫分享給別人(或外部系統)做使用,而是定義一些 Web API,讓使用者透過你開出去的介面,來拿取相應的資源。
想像你要開發一個會員資料庫系統,會員資料都存在資料庫中,如果把資料庫的連線帳號密碼給別人會非常的危險 (即使有做相應的資料庫使用者權限控管,仍然很危險)。
這個時候你就可以定義一些相應的 API 來讓外部服務進行存取。
我們可以利用 Fastify 的 route 方法,定義 endpoints。
import fastify, { FastifyInstance, RouteOptions } from 'fastify'
const server: FastifyInstance = fastify()
const helloRouteOptions: RouteOptions = {
  method: 'GET',
  url: '/',
  handler: (request, reply) => {
    return reply.status(200).send({ message: 'Hello World' })
  }
}
server.route(helloRouteOptions)
.route() 方法吃一個 RouteOptions 的參數,我們可以把想要的 API 的資訊設定上去。以上述程式片段為例,method 是 GET,url 是 /。
就是在定義 GET / 這樣的 API,如果有一個 request 進來到這個 Endpoint,會呼叫 handler 所定義的函式。
handler 要給定的型態是一個 function,這個 function 的第一個參數是 FastifyRequest、第二個參數是 FastifyReply,然後 return 一個 FastifyReply。
我們透過給定 RouteOptions 的值,來定義每個 API Endpoint 的樣子。
method 描述 HTTP Method,用大寫字串定義。例如 GET, POST, PUT, PATCH, DELETE, 等。url,描述路徑,這個 route 代表的路徑。handler,這個 route 收到 request 後的處理函式。errorHandler,自行定義 error 的處理函式。schema,可以定義 request 跟 response 的格式,用於做資料的驗證及序列化。logLevel,定義這個 route 使用的 log 等級。除了上述還有很多 fastify hook 可以設定在這個 route 上。
詳細 RouteOptions 的說明可以參考 Fastify RouteOptions
上述介紹的方式,先定義 RouteOptions,再透過 .route() 的方式,其實有點麻煩,也不易閱讀。
Fastify 提供另一種比較簡潔的寫法,稱為 Shorthand declaration。
對應於不同的 HTTP Method,提供以下幾個方法
fastify.get(path, [options], handler)
fastify.head(path, [options], handler)
fastify.post(path, [options], handler)
fastify.put(path, [options], handler)
fastify.delete(path, [options], handler)
fastify.options(path, [options], handler)
fastify.patch(path, [options], handler)
試著把把上述定義 GET / 會回傳 Hello World 字串的 route,以 Shorthand 的方式改寫。
const server: FastifyInstance = fastify()
server.get('/', (request, reply) => {
  return reply.status(200).send({ message: 'Hello World' })
})
有沒有覺得簡單直覺許多。
.get 表示註冊的是 GET 方法,第一個參數是 url,如果有需要 RouteOptions 可以放在第二個參數,然後接一個 handler function。
因為看起來比較乾淨清楚(不用看一堆 key-value 來判斷這是什麼樣的 API),所以自己在開發比較常用這種寫法。
handler 的使用,該 function 可以是一般的 function 也可以是 async function。
如果處理 request 的需要做一些非同步的工作,如查詢資料庫,用 async function 搭配 await 的寫法非常方便。
server.get('/', async (request, reply) => {
  try {
    const users = await queryUsersFromDb() // async task
    return reply.status(200).send({ users })
  } catch(error) {
    return reply.status(500).send({ error })
  }
})
以上是 fastify route 的基本介紹。